package com.ahpu.lyf.linkedlist;

import java.util.Objects;

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        HeroNode hero1 = new HeroNode(1, "张三");
        HeroNode hero2 = new HeroNode(4, "李四");
        HeroNode hero3 = new HeroNode(7, "王五");
        SingleLinkedList heroLinkedList = new SingleLinkedList();
        heroLinkedList.add(hero1);
        heroLinkedList.add(hero2);
        heroLinkedList.add(hero3);
        heroLinkedList.showLinkedList();
        heroLinkedList.addByOrder(new HeroNode(3,"典韦"));
        heroLinkedList.addByOrder(new HeroNode(2,"李白"));
        heroLinkedList.addByOrder(new HeroNode(2,"韩信"));
        heroLinkedList.addByOrder(new HeroNode(8,"李元芳"));
        heroLinkedList.showLinkedList();
        heroLinkedList.upDate(new HeroNode(7,"女娲"));
        heroLinkedList.showLinkedList();
        heroLinkedList.delete(4);
        heroLinkedList.showLinkedList();
    }
}

class SingleLinkedList {
    //初始化一个头节点
    private final HeroNode head = new HeroNode(0, "");

    /**
     * 向链表添加节点的方法
     * 不考虑编号顺序时
     * 1.找到链表最后的一个节点
     * 2.使最后一个节点的next域指向这个新节点
     * @param heroNode 要添加的节点
     */
    public void add(HeroNode heroNode) {
        //辅助节点用来遍历
        HeroNode temp = head;
        //遍历列表，找到最后一个节点的位置,下一个节点的next域不为null则temp后移
        while (temp.getNext() != null) {
            //没有找到，就将temp后移
            temp = temp.getNext();
        }
        //循环走完temp就指向链表最后一个节点
        temp.setNext(heroNode);
        System.out.println(heroNode.getName()+"：节点添加成功！");
    }

    /**
     * 根据id升序进行插入节点的方法
     * 并且id唯一
     * @param heroNode 要插入的节点
     */
    public void addByOrder(HeroNode heroNode){
        //辅助节点进行遍历
        HeroNode temp=head;
        //一直遍历直到最后一个节点
        while (temp.getNext()!=null){
            //当前节点的编号与要添加节点的编号相等
            if(Objects.equals(temp.getNext().getId(), heroNode.getId())){
                System.out.println(heroNode.getName()+"：编号已存在！");
                break;
            }
            //当前节点的编号小于要插入节点的编号并且当前节点的下一个节点的编号大于要插入的节点的编号，就插入到当前节点的后面
            if (temp.getNext().getId()>heroNode.getId()&&temp.getId()<heroNode.getId()){
                //要插入节点指向当前节点的下一节点
                heroNode.setNext(temp.getNext());
                //当前节点指向要插入的节点
                temp.setNext(heroNode);
                System.out.println(heroNode.getName()+"：节点添加成功！");
                break;
            }
            temp=temp.getNext();
        }
        //循环走完若temp的下一个节点为null则此时temp指向最后一个节点，说明要插入的节点id比链表所有节点的id都大，应该插入到最后面
        if (temp.getNext()==null) {
            temp.setNext(heroNode);
            System.out.println(heroNode.getName() + "：节点添加成功！");
        }
    }

    /**
     * 根据heroNode的id进行修改
     * @param heroNode 传入要修改的节点数据，id为要修改的id，name为要给指定编号修改的值
     */
    public void upDate(HeroNode heroNode){
        //辅助节点用于遍历
        HeroNode temp=head.getNext();
        //当前节点的id与要修改的节点id不相等则后移
        while (!Objects.equals(temp.getId(), heroNode.getId()))
            temp=temp.getNext();
        //修改name
        temp.setName(heroNode.getName());
        System.out.println(temp.getId()+"：节点修改成功");
    }

    /**
     * 根据id删除节点信息
     * @param id 要删除的节点的id
     */
    public void delete(Integer id){
        //辅助节点用于遍历
        HeroNode temp=head;
        //判断链表是否为空
        if (temp.getNext()==null){
            System.out.println("链表为空！");
            return;
        }
        //temp首次指向的是head，所以当下一节点的id与要删除节点id不想等的时候后移
        while (!Objects.equals(temp.getNext().getId(), id))
            temp=temp.getNext();
        //当循环结束时，下一节点就是要删除的节点,让当前节点的next指向下一节点的下一节点，下一个节点即要删除的节点后续会被gc回收
        temp.setNext(temp.getNext().getNext());
        System.out.println(id+"：节点删除成功！");
    }


    /**
     * 输出链表所有节点的方法
     */
    public void showLinkedList() {
        //判断链表是不是为空
        if (head.getNext() == null) {
            System.out.println("链表为空！");
            return;
        }
        //需要辅助节点来遍历链表,并将temp指向第一个元素（一定存在，上面判断过）
        HeroNode temp = head.getNext();
        System.out.println("\n开始打印链表节点：");
        //思路,temp节点下一个节点不为null，则打印该节点的信息并将temp后移
        while (temp.getNext() != null) {
            //打印temp节点的信息
            System.out.println(temp);
            //辅助节点后移
            temp = temp.getNext();
        }
        //打印一下最后一个节点
        System.out.println(temp);
        System.out.println("链表节点打印完毕！");
    }

}


//保存HeroNode，每个HeroNode对象就是一个节点
class HeroNode {
    private Integer id;
    private String name;
    private HeroNode next;  //指向下一个节点

    public HeroNode(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getNext() {
        return next;
    }

    public void setNext(HeroNode next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}